﻿#pragma once

#include <unordered_map>
#include <string>
#include <cstdint>
#include <vector>

#include "../util/box_std_allocator.hh"

namespace kratos {
namespace service {

class ServiceBox;

/**
 * 容器地址信息 
 */
struct Host {
    std::string   host;       ///< 容器地址
    std::uint64_t channel_id; ///< 管道
};

/**
 * 容器信息 
 */
struct HostInfo {
    kratos::service::PoolVector<Host> host_vec; ///< 容器地址信息数组
    std::size_t                       index;    ///< 轮询索引
};

/**
 * 服务层，维护服务到其他容器的管道，按需建立连接
 */
class ServicelLayer {
  using ServiceMap = kratos::service::PoolUnorederedMap<std::string, HostInfo>;

  ServiceMap  service_map_;  ///< 已建立连接的服务表
  ServiceBox* box_{nullptr}; ///< 服务容器

public:
  /**
   * 构造
   *
   * \param box 服务容器
   */
  ServicelLayer(ServiceBox* box);
  /**
   * 析构 
   */
  ~ServicelLayer();
  /**
   * 当连接建立时调用
   *
   * \param name 服务名
   * \param channel_id 管道ID
   */
  auto on_connect(const std::string& name, std::uint64_t channel_id)->void;
  /**
   * 当连接关闭时调用
   *
   * \param name 服务名
   * \param channel_id 管道ID
   */
  auto on_close(const std::string& name, std::uint64_t channel_id)->void;
  /**
   * 从缓存内获取服务对应的管道，如果不存在则尝试建立到其他容器的连接并立即返回0
   *
   * \param service_name 服务名
   * \return channel_id 管道ID
   */
  auto get_channel(const std::string& service_name)->std::uint64_t;
  /**
   * 从缓存内获取服务对应的管道，如果不存在则立即返回0
   *
   * \param service_name 服务名
   * \return channel_id 管道ID
   */
  auto try_get_channel(const std::string& service_name)->std::uint64_t;
  /**
   * 获取所有已经连接的服务 
   */
  auto get_remote_service()-> const ServiceMap&;

private:
  /**
   * 服务变化监听函数 
   */
  auto service_listener(const std::string& name,
      const std::vector<std::string>& hosts)->void;
  /**
   * 连接到其他容器
   * 
   * \param name 服务名
   * \param host 容器地址
   * \return true或false
   */
  auto connect_to_host(const std::string& name, const std::string& host)->bool;
};

}
}

